package isquirrel.beans;

import isquirrel.network.ProfileComparator;
import isquirrel.recommender.DynamicRecommender;
import isquirrel.recommender.Recommender;
import isquirrel.util.HibernateUtil;
import isquirrel.util.URL;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class User{

	private Long userID;
	private String firstName;
	private String lastName;
	private Date dob;
	private String sex;
	private String username;
	private String password;
	private String token;
	private Set<Interest> interests = new HashSet<Interest>();
	private Set<User> friends = new HashSet<User>();
	private Set<Url> urls = new HashSet<Url>();
	//	private Map<String, UserInterest> interests = new HashMap<String,UserInterest>();
	private Long fbID;
	private Integer isProfileInit;
	private Set<Property> properties = new HashSet<Property>(); // dynamic profile

	public User() {}
	
	public User(String firstName, 
				String lastName,
				String username, 
				String password,
				Date dob,
				String sex,
				String token,
				Long fbID,
				Integer isProfileInit
				) {
		
		this.firstName = firstName;
		this.lastName = lastName;
		this.dob = dob;
		this.sex = sex;
		this.username = username;
		this.token = token;
		this.password = password;
		this.fbID = fbID;
		this.isProfileInit = isProfileInit;
	}
		
	public Long getUserID() {
		return userID;
	}
	
	@SuppressWarnings("unused")
	private void setUserID(Long userID) {
		this.userID = userID;
	}
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	
	public String getFullName() {
		return this.getFirstName() + " " + this.getLastName();
	}
	
	public void setDob(Date dob) {
		this.dob = dob;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public Date getDob() {
		return dob;
	}
	public String getDob_nice(){
		return new SimpleDateFormat("dd/MM/yyyy").format(dob);
	}
	public String getSex() {
		return sex;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	
	public Set<Interest> getInterests() {
		return interests;
	}
	
	public List<String> getInterests_labels(){
		
		List<String> labels = new LinkedList<String>();
		for (Interest i: interests){
			String[] itokens = i.getLabel().split(" ");
			for (int j = 0; j < itokens.length; ++j){
				labels.add(itokens[j].toUpperCase());
			}
		}
		return labels;
	}

	public void setInterests(Set<Interest> interests) {
		this.interests = interests;
	}
	
	public Set<User> getFriends() {
		return friends;
	}

	public void setFriends(Set<User> friends) {
		this.friends = friends;
	}

	public String getToken(){
		return this.token;
	}
	
	public void setToken(String token){
		this.token = token;
	}
	
	public void setFbID(Long fbID){
		this.fbID = fbID;
	}
	
	public Long getFbID(){
		return fbID;
	}
	
	public Integer getIsProfileInit(){
		return isProfileInit;	
	} 
	
	public void setIsProfileInit(Integer init){
		isProfileInit = init;
	}
	
	public JSONObject toJSON() {
		JSONObject user = new JSONObject();
		JSONArray userInterests = new JSONArray();
		try {
			
//			for (Interest ui : interests)  
//				userInterests.put(ui.toJSON().toString());
			
			user.put("userID", userID);
			user.put("username", username);
			user.put("firstName", firstName);
			user.put("lastName", lastName);
			user.put("password", password);
			user.put("token", token);
			user.put("interests", userInterests);
			user.put("fbid", fbID);
			user.put("sex", sex);
			user.put("dob", new SimpleDateFormat("dd/mm/yyyy").format(dob));
			
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return user;
	}
	
	public void addFriend(User friend) {
		this.friends.add(friend);
	}
	
	public void removeFriend(User friend) {
		this.friends.remove(friend);
	}
	
	@Override
	public boolean equals(Object other){
		if (other instanceof User) {
			return this.userID == ((User) other).getUserID();
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		return this.getUserID().hashCode();
	}

	public boolean addInterest(Interest i) {
		if (!interests.contains(i)) {
			HibernateUtil.getSession().saveOrUpdate(i);
			interests.add(i);
			return true;
		}
		return false;
	}
	
	public Set<Url> getUrls() {
		return urls;
	}
	
	public List<Url> getLikedUrls(){
		return Recommender.getLikes(this, -1);
	}

	public void setUrls(Set<Url> urls) {
		this.urls = urls;
	}
	
	public int addUrl(Url url) {
		if (!this.urls.contains(url)){
			HibernateUtil.getSession().saveOrUpdate(url);
			this.urls.add(url);
			return 1; // the url was not in the db
		}
		else{
			if (getLikedUrls().contains(url)){
				return -1; // ie the user has already liked the url
			}
			else{
				Url urlfromdb = Recommender.getUrl(userID,url.getAddress());
				if (urlfromdb == null) return 0;
				urlfromdb.setLiked(url.isLiked());
				urlfromdb.setThumb(url.getThumb());
				HibernateUtil.getSession().saveOrUpdate(urlfromdb); 
				return 0; // the url was one of the recommendations but it was not liked before
			}
		}
	}
	
	public Set<Property> getProperties() {
		return properties;
	}

	public void setProperties(Set<Property> properties) {
		this.properties = properties;
	}
	
	public Property getProperty(Property property) {
		for (Property p : properties) 
			if (p.equals(property))
				return p;
		return null;
	}
	
	public void addProperty(Property property) {
		if (properties.contains(property)) {
			Property p = getProperty(property);
			p.setFrequency(p.getFrequency()+1);
		} else {
			property.setFrequency(1);
			properties.add(property);
		}
		HibernateUtil.getSession().saveOrUpdate(property);
	}
	
	public double compare(User u) {
		return ProfileComparator.compareUserProfiles(this, u);
	}


	public String getKeyword() {
		final int howMany = 35;
		Set<String> ignore = new HashSet<String>();
		for(Property p : this.properties) {
			if ( p.getAttribute().contains("type")){
				ignore.add(p.getAttribute());
			}
		}
		List<Property> frequentProperties 
			= DynamicRecommender.getFrequentProperties(this, howMany, ignore);
		
		Property chooseOne = frequentProperties.get(
				Math.abs(new Random().nextInt()) % frequentProperties.size()
				);
		
		String keyword = URL.getTitle(chooseOne.getValue());
		if( keyword.startsWith("Category:") )
			keyword = keyword.replaceFirst("Category:", "");
		
		return keyword;
	}
	
	public boolean hasKeywords(){
		
		return (DynamicRecommender.getFrequentProperties(this, 1, null).size() > 0);
		
	}
	
//	public Map<String, UserInterest> getInterests() {
//		return interests;
//	}
//	public void setInterests(Map<String, UserInterest> interests) {
//		this.interests = interests;
//	}
}

